package com.terren.webservice.handler.basic;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.httpclient.HttpException;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.terren.common.util.BeanUtil;
import com.terren.common.util.DateUtil;
import com.terren.common.util.JsonUtil;
import com.terren.webservice.common.entity.DataType;
import com.terren.webservice.common.entity.WebserviceType;
import com.terren.webservice.common.tools.HttpConnectTool;
import com.terren.webservice.exception.BadRequestException;
import com.terren.webservice.exception.ResponseDataNullException;
import com.terren.webservice.exception.UrlNullException;

/**
 * webservice数据处理 基础类 ，
 * 
 * 
 */
public abstract class BasicWebserviceHandler {

	protected Logger log = LoggerFactory.getLogger(this.getClass());
	protected String url;// 地址
	protected DataType returnType; // 返回数据类型
	protected WebserviceType webserviceType; // webservice 实现方式 (rest http
												// 以后需要在扩展)
	protected StringBuffer rspData;// 返回数据
	private String xml_root = "data/bean";// 默认 xml data节点
	private String json_root = "data"; // 默认 json data 节点

	public BasicWebserviceHandler() {
		this.returnType = DataType.JSON;
		this.webserviceType = WebserviceType.RESTFUL;
	}

	protected abstract String getXml_root();
	protected abstract String getJson_root();
	protected abstract void handleJson(StringBuffer json);
	protected abstract void handleXml(StringBuffer xml);
	
	/**
	 * 调用webservice 接口 返回数据
	 * 
	 * @return
	 */
	public String getData() throws UrlNullException, HttpException,
			BadRequestException {
		if (getUrl() == null || getUrl().equals("")) {
			throw new UrlNullException("interface url is null");
		}
		log.info("************************interface url***********************************");
		log.info(getUrl());
		try {
			switch (webserviceType) {
			case RESTFUL:// http 接口：
				rspData = new StringBuffer(HttpConnectTool.getHttp(getUrl()));
				break;

			case SOAP:
				break;
			default:
				rspData = new StringBuffer(HttpConnectTool.getHttp(getUrl()));
				break;
			}
		} catch (IOException e) {
			log.error("BasicReportWebserviceHandler  getData error" + e);
		}
		return rspData.toString();
	}

	/**
	 * xml/json数据源转换 List<ReportData>
	 * 
	 * @param url
	 * @return
	 * @throws UrlNullException
	 * @throws HttpException
	 * @throws BadRequestException
	 * @throws ResponseDataNullException
	 */
	public <T> List<T> getReportData(Class<T> clazz) throws UrlNullException,
			HttpException, BadRequestException, ResponseDataNullException {
		List<T> dataList = null;
		getData();
		if (rspData != null) {
			switch (returnType) {
			case XML:
				dataList = initDataListFromXml(clazz);
				break;

			case JSON:
				// json tools 格式化 data 返回ReportData
				dataList = initDataListFromJson(clazz);

				break;
			}
		}
		if (dataList.isEmpty()) {
			// throw new ResponseDataNullException("response data is null");
		} else {
			//postHandler(dataList);
		}

		return dataList;
	}
	//protected abstract <T> void postHandler(List<T> list);
	public <T> List<T> fromJsonList(String json, Class<T> clazz) {
		List<T> lst = new ArrayList<T>();
		try {
			JsonArray array = new JsonParser().parse(json).getAsJsonArray();
			for (final JsonElement elem : array) {
				lst.add(new Gson().fromJson(elem, clazz));
			}
		} catch (Exception e) {
		}
		return lst;
	}

	public <T> List<T> initDataListFromJson(Class<T> clazz) {
		handleJson(rspData);// 预处理
		String json = rspData.toString();
		if (getJson_root() != null) {
			this.json_root = getJson_root();
		}
		String data = JsonUtil.filterJson(json, this.json_root);
		return fromJsonList(data, clazz);
	}

	/**
	 * 
	 * @param xml
	 * @return
	 */
	private <T> List<T> initDataListFromXml(Class<T> clazz) {
		if (getXml_root() != null) {
			this.xml_root = getXml_root();
		}
		String nodeName = this.xml_root;
		handleXml(rspData);
		String xmlStr = rspData.toString();
		List<T> list = new ArrayList<T>();
		try {
			if (null != xmlStr && !"".equals(xmlStr)) {
				Document document = DocumentHelper.parseText(xmlStr);
				Element root = document.getRootElement();
				List<?> nodes = root.selectNodes(nodeName);
				if (null != nodes) {
					Iterator<?> iterator = nodes.iterator();
					while (iterator.hasNext()) {
						Element element = (Element) iterator.next();
						T rd = fromXmlToBean(element, clazz);
						list.add(rd);
					}
				}
			}

		} catch (Exception e) {
			log.error("initDataListFromXml error", e);
		}
		return list;
	}

	public <T> T fromXmlToBean(Element rootElt, Class<T> pojo) throws Exception {
		// 首先得到pojo所定义的字段
		Field[] fields = pojo.getDeclaredFields();
		// 根据传入的Class动态生成pojo对象
		T obj = pojo.newInstance();
		for (Field field : fields) {
			// 设置字段可访问（必须，否则报错）
			field.setAccessible(true);
			// 得到字段的属性名
			String name = field.getName();

			// 这一段的作用是如果字段在Element中不存在会抛出异常，如果出异常，则跳过。
			try {
				rootElt.elementTextTrim(name);
			} catch (Exception ex) {
				continue;
			}
			if (rootElt.elementTextTrim(name) != null
					&& !"".equals(rootElt.elementTextTrim(name))) {
				// 根据字段的类型将值转化为相应的类型，并设置到生成的对象中。
				if (field.getType().equals(Long.class)
						|| field.getType().equals(long.class)) {
					field.set(obj,
							Long.parseLong(rootElt.elementTextTrim(name)));
				} else if (field.getType().equals(String.class)) {
					field.set(obj, rootElt.elementTextTrim(name));
				} else if (field.getType().equals(Double.class)
						|| field.getType().equals(double.class)) {
					field.set(obj,
							Double.parseDouble(rootElt.elementTextTrim(name)));
				} else if (field.getType().equals(Integer.class)
						|| field.getType().equals(int.class)) {
					field.set(obj,
							Integer.parseInt(rootElt.elementTextTrim(name)));
				} else if (field.getType().equals(java.util.Date.class)) {
					field.set(obj, DateUtil.stringToDate(
							rootElt.elementTextTrim(name),
							"yyyy-MM-dd HH:mm:ss"));
				} else {
					continue;
				}
			}
		}
		return obj;
	}

	
	/**
	 * url参数赋值
	 * @param url
	 * @param param
	 * @return
	 */
	public <T> String formatUrl(String url,T param){
		Map<String, String> paramMap = BeanUtil.getFieldValueMap(param);
		return formatUrl(url, paramMap);
	}
	
	/**
	 * url参数赋值
	 * @param url
	 * @param paramMap
	 * @return
	 */
	public String formatUrl(String url,Map<String, String> paramMap){
		log.info(" parameters:"+paramMap.toString());
		for (Map.Entry<String, String> entry : paramMap.entrySet()) {  
			String p_paramName = "{"+ entry.getKey() + "}"; 
			url = StringUtils.replace(url, p_paramName, entry.getValue());
		}
		//log.info(" url:"+url);
		return url;
	}
	
	
	
	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public DataType getReturnType() {
		return returnType;
	}

	public void setReturnType(DataType returnType) {
		this.returnType = returnType;
	}

	public WebserviceType getWebserviceType() {
		return webserviceType;
	}

	public void setWebserviceType(WebserviceType webserviceType) {
		this.webserviceType = webserviceType;
	}
}
